package com.gitee.apanlh.util.setting;

import com.gitee.apanlh.exp.StreamReadException;
import com.gitee.apanlh.util.encode.CharsetCode;
import com.gitee.apanlh.util.io.FileIOUtils;
import com.gitee.apanlh.util.io.IOUtils;
import com.gitee.apanlh.util.io.ReadLineIterator;
import com.gitee.apanlh.util.valid.ValidParam;

import java.io.BufferedReader;
import java.net.URL;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 	配置文件加载器
 * 	<br>加载配置文件内容等操作
 * 	<br>不限外部文件、资源、YML、Properties、INI等
 * 
 * 	@author Pan
 */
public class ConfigLoader {
	
	/** URL资源 */
	private URL url;
	/** 地址 */
	private String path;
	/** 配置文件键 */
	private String key;
	/** 字符编码 */
	private String charset;
	/** 资源协议 */
	private String protocol;
	
	/**	
	 * 	构造函数-加载资源
	 * 	<br>默认UTF-8字符集编码
	 * 	
	 * 	@author Pan
	 * 	@param 	url		URL资源
	 */
	public ConfigLoader(URL url) {
		this(url, CharsetCode.UTF_8);
	}
	
	/**	
	 * 	构造函数-加载资源
	 * 	<br>自定义字符集编码
	 * 	
	 * 	@author Pan
	 * 	@param 	url		URL资源
	 * 	@param 	charset	字符集编码
	 */
	public ConfigLoader(URL url, String charset) {
		this.url = url;
		this.path = url.getFile();
		if (ValidParam.isNotNull(this.path)) {
			this.path = this.path.substring(1);
			this.key = this.path.substring(this.path.lastIndexOf('/') + 1);
			this.protocol = this.url.getProtocol();  
		}
		this.charset = charset;
	}
	
	/**
	 * 	加载配置文件
	 * 	<br>普通配置文件形式，键值对形式
	 * 	<br>自定义URL资源
	 * 	<br>自定义字符集编码
	 * 	
	 * 	@author Pan
	 * 	@return	Map
	 */
	public Map<String, String> loadFromProperties() {
		ConfigParse<String, String> configParse = new PropertiesParse();
		return handleConfigParse(configParse, reader -> {
			ReadLineIterator readLine = FileIOUtils.readLine(reader);
			
			while (readLine.hasNext()) {
				configParse.parse(readLine.next());
			}
		});
	}
	
	/**
	 * 	加载配置文件
	 * 	<br>Yaml格式(.yml等文件)
	 * 	<br>自定义URL资源
	 * 	<br>自定义字符集编码
	 * 	
	 * 	@author Pan
	 * 	@return	Map
	 */
	public Map<String, LinkedHashMap<String, Object>> loadFromYaml() {
		ConfigParse<String, LinkedHashMap<String, Object>> configParse = new YamlParse();
		return handleConfigParse(configParse, reader -> {});
	}
	
	/**
	 * 	用于执行解析/加载时拦截操作，避免每个加载类型都要重复关闭流及特殊操作
	 * 	
	 * 	@author Pan
	 * 	@param 	configParse		配置解析器
	 * 	@param 	configHandler	配置拦截器
	 * 	@return	Map
	 */
	private <K, V> Map<K, V> handleConfigParse(ConfigParse<K, V> configParse, ConfigHandler configHandler) {
		BufferedReader reader = null;
		try {
			reader = configParse.load(this.url, this.charset);
			configParse.parse(reader);
			configHandler.handler(reader);
			return configParse.getResolveMap();
		} catch (Exception e) {
			throw new StreamReadException(e.getMessage(), e);
		} finally {
			IOUtils.close(reader);
		}
	}
	
	/**	
	 * 	设置唯一键
	 * 	
	 * 	@author Pan
	 * 	@param 	key	唯一键
	 */
	public void setKey(String key) {
		this.key = key;
	}

	/**
	 * 	设置字符集编码
	 * 	
	 * 	@author Pan
	 * 	@param 	charset	字符集编码
	 */
	public void setCharset(String charset) {
		this.charset = charset;
	}

	/**	
	 * 	获取配置文件中的绝对路径
	 * 	
	 * 	@author Pan
	 * 	@return	String
	 */
	public String getPath() {
		return this.path;
	}
	
	/**	
	 * 	将文件名作为key
	 * 	
	 * 	@author Pan
	 * 	@return	String
	 */
	public String getKey() {
		return this.key;
	}
	
	/**	
	 * 	获取资源协议
	 * 	
	 * 	@author Pan
	 * 	@return	String
	 */
	public String getProtocol() {
		return protocol;
	}

	/**	
	 * 	创建配置加载器
	 * 	<br>默认UTF-8字符集编码
	 * 	
	 * 	@author Pan
	 * 	@param 	url		URL资源
	 * 	@return	ConfigLoader
	 */
	public static ConfigLoader create(URL url) {
		return new ConfigLoader(url);
	}
	
	/**	
	 * 	创建配置加载器
	 * 	<br>自定义字符集编码
	 * 	
	 * 	@author Pan
	 * 	@param 	url		URL资源
	 * 	@param 	charset	字符集编码
	 * 	@return	ConfigLoader
	 */
	public static ConfigLoader create(URL url, String charset) {
		return new ConfigLoader(url, charset);
	}
}
